/**
 * Copyright (C) 2011 The Android Open Source Project 
 * Emial : guoyil199@163.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package com.db;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;

/**
 * @author Administrator
 * @Email guoyil199@163.com
 * @version V1.0
 * @Date 2015年7月27日 下午2:39:02
 * @Title <B>todo</B>
 * @Description <pre>
 * 		数据库管理类，具备增删改查操作。
 *      增删改 --> 操作一个sql语句，并且有返回值。
 *      查询    --> 1. 返回一个游标类型
 *              2. 返回一个List<Object>
 *              3. 返回一个List<Map<String, Object>>
 * </pre>
 */
public abstract class DaoHelper {
	private AtomicInteger mOpenCounter = new AtomicInteger();
	private DBHelper dbHelper;
	private SQLiteDatabase mRDB,mWDB;

	private class DBHelper extends SQLiteOpenHelper {
		private static final String DB_NAME = "app.db";
		private static final int DB_VERSION = 1;

		public DBHelper(Context ctx) {
			this(ctx, DB_NAME, null, DB_VERSION);
		}

		public DBHelper(Context context, String name, CursorFactory factory,
				int version) {
			super(context, name, factory, version);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * android.database.sqlite.SQLiteOpenHelper#onCreate(android.database
		 * .sqlite.SQLiteDatabase)
		 */
		@Override
		public void onCreate(SQLiteDatabase arg0) {
			
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database
		 * .sqlite.SQLiteDatabase, int, int)
		 */
		@Override
		public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

		}
	}

	/**
	 * 构造函数
	 * @param context
	 *            上下文对象
	 */
	public DaoHelper(Context context) {
		dbHelper = new DBHelper(context);
	}


	public synchronized void openDatabase() {
		if (mOpenCounter.incrementAndGet() == 1) {
			// Opening new database
			mRDB = dbHelper.getReadableDatabase();
			mWDB=dbHelper.getWritableDatabase();
		}
	}
	
	/**
	 * 关闭数据库
	 */
	public synchronized void close() {
		if(mOpenCounter.incrementAndGet() == 1) {
			if (mRDB.isOpen())
				mRDB.close();
			if(mWDB.isOpen()){
				mWDB.close();
			}
			if (dbHelper != null)
				dbHelper.close();
		}
	}

	
	/**
	 * 插入数据
	 * 
	 * @param sql
	 *            执行更新操作的sql语句
	 * @param bindArgs
	 *            sql语句中的参数,参数的顺序对应占位符顺序
	 * @return result 返回新添记录的行号，与主键id无关
	 */
	public Long insert(String sql, String[] bindArgs) throws Exception {
		long result = 0;
		if (mWDB.isOpen()) {
			SQLiteStatement statement = mWDB.compileStatement(sql);
			if (bindArgs != null) {
				int size = bindArgs.length;
				for (int i = 0; i < size; i++) {
					// 将参数和占位符绑定，对应
					statement.bindString(i + 1, bindArgs[i]);
				}
				result = statement.executeInsert();
				statement.close();
			}
		} else {
			Log.i("info", "数据库已关闭");
		}
		return result;
	}

	/**
	 * 插入数据
	 * 
	 * @param table
	 *            表名
	 * @param values
	 *            要插入的数据
	 * @return result 返回新添记录的行号，与主键id无关
	 */
	public Long insert(String table, ContentValues values) {
		long result = 0;
		if (mWDB.isOpen()) {
			result = mWDB.insert(table, null, values);
		}
		return result;
	}

	/**
	 * 更新数据
	 * 
	 * @param sql
	 *            执行更新操作的sql语句
	 * @param bindArgs
	 *            sql语句中的参数,参数的顺序对应占位符顺序
	 */
	public void update(String sql, String[] bindArgs) throws Exception {
		if (mWDB.isOpen()) {
			SQLiteStatement statement = mWDB.compileStatement(sql);
			if (bindArgs != null) {
				int size = bindArgs.length;
				for (int i = 0; i < size; i++) {
					statement.bindString(i + 1, bindArgs[i]);
				}
				statement.execute();
				statement.close();
			}
		} else {
			Log.i("info", "数据库已关闭");
		}
	}

	/**
	 * 更新数据
	 * 
	 * @param table
	 *            表名
	 * @param values
	 *            表示更新的数据
	 * @param whereClause
	 *            表示SQL语句中条件部分的语句
	 * @param whereArgs
	 *            表示占位符的值
	 * @return
	 */
	public int updata(String table, ContentValues values,
			String whereClause, String[] whereArgs) {
		int result = 0;
		if (mWDB.isOpen()) {
			result = mWDB.update(table, values, whereClause,whereArgs);
		}
		return result;
	}

	/**
	 * 删除数据
	 * 
	 * @param sql
	 *            执行更新操作的sql语句
	 * @param bindArgs
	 *            sql语句中的参数,参数的顺序对应占位符顺序
	 */
	public void delete(String sql, String[] bindArgs) throws Exception {
		if (mWDB.isOpen()) {
			SQLiteStatement statement = mWDB.compileStatement(sql);
			if (bindArgs != null) {
				int size = bindArgs.length;
				for (int i = 0; i < size; i++) {
					statement.bindString(i + 1, bindArgs[i]);
				}
				Method[] mm = statement.getClass().getDeclaredMethods();
				for (Method method : mm) {
					Log.i("info", method.getName());
					/**
					 * 反射查看是否能获取executeUpdateDelete方法 查看源码可知
					 * executeUpdateDelete是public的方法，但是好像被隐藏了所以不能被调用，
					 * 利用反射貌似只能在root以后的机器上才能调用，小米是可以，其他机器却不行，所以还是不能用。
					 */
				}
				statement.execute();
				statement.close();
			}
		} else {
			Log.i("info", "数据库已关闭");
		}
	}

	/**
	 * 删除数据
	 * 
	 * @param table
	 *            表名
	 * @param whereClause
	 *            表示SQL语句中条件部分的语句
	 * @param whereArgs
	 *            表示占位符的值
	 * @return
	 */
	public int delete(String table, String whereClause, String[] whereArgs) {
		int result = 0;
		if (mWDB.isOpen()) {
			result = mWDB.delete(table, whereClause, whereArgs);
		}
		return result;
	}

	/**
	 * 查询数据
	 * 
	 * @param searchSQL
	 *            执行查询操作的sql语句
	 * @param selectionArgs
	 *            查询条件
	 * @return 返回查询的游标，可对数据自行操作，需要自己关闭游标
	 */
	public Cursor query(String sql, String[] selectionArgs)
			throws Exception {
		if (mRDB.isOpen()) {
			Cursor cursor = mRDB.rawQuery(sql, selectionArgs);
			if (cursor != null) {
				cursor.moveToFirst();
			}
			return cursor;
		}
		return null;
	}

	public <T>List<T>query(String table,String[] columns,String whereCase,String[] selectionArgs,T t) throws Exception{
		List<T> mList = new ArrayList<T>();
		if(mRDB.isOpen()){
			Cursor cursor=mRDB.query(table, columns, whereCase, selectionArgs, null, null, null);
			Field[] f;
			if (cursor != null && cursor.getCount() > 0) {
				while (cursor.moveToNext()) {
					f = t.getClass().getDeclaredFields();
					for (int i = 0; i < f.length; i++) {
						// 为JavaBean 设值
						invokeField(t, f[i].getName(),cursor.getString(cursor.getColumnIndex(f[i].getName())));
					}
					mList.add(t);
				}
			}
			cursor.close();
		}
		return mList;
	}
	
	
	/**
	 * 查询数据
	 * 
	 * @param sql
	 *            执行查询操作的sql语句
	 * @param selectionArgs
	 *            查询条件
	 * @param object  Object的对象
	 * @return List<Object> 返回查询结果
	 */
	public <T> List<T> query(String sql, String[] selectionArgs,T t) throws Exception {
		List<T> mList = new ArrayList<T>();
		if (mRDB.isOpen()) {
			Cursor cursor = mRDB.rawQuery(sql, selectionArgs);
			Field[] f;
			if (cursor != null && cursor.getCount() > 0) {
				while (cursor.moveToNext()) {
					f = t.getClass().getDeclaredFields();
					for (int i = 0; i < f.length; i++) {
						// 为JavaBean 设值
						invokeField(t, f[i].getName(),cursor.getString(cursor.getColumnIndex(f[i].getName())));
					}
					mList.add(t);
				}
			}
			cursor.close();
		} else {
			Log.i("info", "数据库已关闭");
		}
		return mList;
	}

	/**
	 * 查询数据
	 * 
	 * @param sql
	 *            执行查询操作的sql语句
	 * @param selectionArgs
	 *            查询条件
	 * @param object
	 *            Object的对象
	 * @return List<Map<String, Object>> 返回查询结果
	 * @throws Exception
	 */
	public List<Map<String, String>> queryToMap(String sql,String[] selectionArgs, String t) throws Exception {
		List<Map<String, String>> mList = new ArrayList<Map<String, String>>();
		if (mRDB.isOpen()) {
			Cursor cursor = mRDB.rawQuery(sql, selectionArgs);
			Field[] f;
			Map<String, String> map;
			if (cursor != null && cursor.getCount() > 0) {
				while (cursor.moveToNext()) {
					map = new HashMap<String, String>();
					f = t.getClass().getDeclaredFields();
					for (int i = 0; i < f.length; i++) {
						
						map.put(f[i].getName(),cursor.getString(cursor.getColumnIndex(f[i].getName())));
					}
					mList.add(map);
				}
			}
			cursor.close();
		} else {
			Log.i("info", "数据库已关闭");
		}
		return mList;
	}

	/**
	 * java反射bean的set方法
	 * 
	 * @param objectClass
	 * @param fieldName
	 * @return
	 */
	public Method getSetMethod(Class<?> objectClass, String fieldName) {
		try {
			Class<?>[] parameterTypes = new Class[1];
			Field field = objectClass.getDeclaredField(fieldName);
			parameterTypes[0] = field.getType();
			
			StringBuffer sb = new StringBuffer();
			sb.append("set");
			sb.append(fieldName.substring(0, 1).toUpperCase());
			sb.append(fieldName.substring(1));
			
			Method method = objectClass.getMethod(sb.toString(), parameterTypes);
			return method;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 执行set方法
	 * 
	 * @param object
	 *            执行对象
	 * @param fieldName
	 *            属性
	 * @param value
	 *            值
	 */
	public <T> void invokeSetMethod(T t, String fieldName, Object value) {
		Method method = getSetMethod(t.getClass(), fieldName);
		try {
			method.invoke(t, new Object[] { value });
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private <T> void invokeField(T obj, String fieldName, Object value) {
		// 得到单一属性方法（只能为公有的）
		try {
			Field field = obj.getClass().getField(fieldName);
			if (field != null) {
				field.setAccessible(true);
				// Class fieldType = field.getType();
				field.set(obj, value);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private boolean isBasicType(Class typeClass) {
		if (typeClass.equals(Integer.class) || typeClass.equals(Long.class)
				|| typeClass.equals(Float.class)
				|| typeClass.equals(Double.class)
				|| typeClass.equals(Boolean.class)
				|| typeClass.equals(Byte.class)
				|| typeClass.equals(Short.class)
				|| typeClass.equals(String.class)) {

			return true;

		} else {
			return false;
		}
	}
}
